package com.taobaolite.item;

import com.taobaolite.user.store.Store;
import com.taobaolite.user.store.StoreRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;

import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Service
public class ItemService {
    private final ItemRepository itemRepo;
    private final StoreRepository storeRepo;

    @Autowired
    public ItemService(ItemRepository itemRepo, StoreRepository storeRepo) {
        this.itemRepo = itemRepo;
        this.storeRepo = storeRepo;
    }

    public ItemBody getItem(Long itemId, Long userId) {
        Item item = itemRepo.findById(itemId)
                .orElseThrow(() -> new ResponseStatusException(
                        HttpStatus.NOT_FOUND,
                        "Item with ID " +
                                itemId +
                                " does not exist."
                ));
        return new ItemBody(item);
    }

    public List<ItemBody> getItems(Long storeId, Long type) {
        List<ItemBody> itemBodyList = new ArrayList<>();
        List<Item> itemList = itemRepo.findAll();

        // Apply store filter
        if (storeId != null) {
            if (storeRepo.existsById(storeId)) {
                itemList.removeIf(i -> !Objects.equals(i.getStore().getStoreId(), storeId));
            } else {
                throw new ResponseStatusException(
                        HttpStatus.NOT_FOUND,
                        "Store with ID " +
                                storeId +
                                " does not exist."
                );
            }
        }

        // Apply type filter;
        if (type != null) {
            int numOfDigits = getNumOfDigits(type);
            Long fromType = new Double(type * Math.pow(10, 8 - numOfDigits)).longValue();
            Long toType = new Double((type + 1) * Math.pow(10, 8 - numOfDigits)).longValue();
            List<Item> itemsOfType = itemRepo.findByType(fromType, toType);
            itemList.removeIf(i -> !itemsOfType.contains(i));
        }

        // Throw exception if list is empty
        if (itemList.size() == 0) {
            throw new ResponseStatusException(
                    HttpStatus.NOT_FOUND,
                    "Cannot find item of request. Try adjusting your filter."
            );
        }

        for (Item item : itemList) {
            itemBodyList.add(new ItemBody(item));
        }

        return itemBodyList;
    }

    @Transactional
    public ItemBody addItem(ItemBody itemBody) {
        Store store = storeRepo.findById(itemBody.getStoreId())
                .orElseThrow(() -> new ResponseStatusException(
                        HttpStatus.NOT_FOUND,
                        "Store with ID " +
                                itemBody.getStoreId() +
                                " does not exist."
                ));

        Long generatedId = generateItemId(itemBody.getItemId());

        Item item = new Item(
                generatedId,
                itemBody.getName(),
                itemBody.getPrice(),
                itemBody.getDescription(),
                itemBody.getAmount(),
                store
        );

        itemRepo.save(item);

        itemBody.setItemId(generatedId);

        return itemBody;
    }

    private int getNumOfDigits(Long num) {
        int i;
        for (i = 0; num > 0; i++) {
            num = num / 10;
        }
        return i;
    }

    private int getNumOfZero(Long num) {
        int i;
        int remainder = 0;
        for (i = 0; remainder == 0; i++) {
            remainder = (int) (num % 10);
            num /= 10;
        }
        return i - 1;
    }

    public Long generateItemId(Long id) {
        int numOfZero = getNumOfZero(id);
        List<Item> itemList = itemRepo.findByType(id, id + 10L * (numOfZero - 1));
        return id + itemList.size() + 1;
    }

    public void updateItem(ItemBody itemBody) {
        Item item = itemRepo.findById(itemBody.getItemId())
                .orElseThrow(() -> new ResponseStatusException(
                        HttpStatus.NOT_FOUND,
                        "Item with ID " +
                                itemBody.getItemId() +
                                " can not be found."
                ));

        // Update all fields
        item.setAmount(itemBody.getAmount());
        item.setDescription(itemBody.getDescription());
        item.setImageDir(itemBody.getImageDir());
        item.setName(itemBody.getName());
        item.setPrice(itemBody.getPrice());
    }

    @Transactional
    public void deleteItem(Long itemId) {
        itemRepo.findById(itemId)
                .orElseThrow(() -> new ResponseStatusException(
                        HttpStatus.NOT_FOUND,
                        "Item with ID " + itemId + " does not exist."
                )).setAmount(-1L);

        // TODO: 数据库理论上暂时无法删除记录
    }
}
